package com.tbit.uqbike.client.filter.servlet;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tbit.uqbike.client.dto.CommonHeaderDTO;
import com.tbit.uqbike.client.dto.EventPutDTO;
import com.tbit.uqbike.client.pojo.User;
import com.tbit.uqbike.client.pojo.event.EventFilterConfigDO;
import com.tbit.uqbike.client.service.TokenService;
import com.tbit.uqbike.client.service.event.EventFilterConfigService;
import com.tbit.uqbike.client.service.event.EventHandleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * 埋点过滤器
 *
 * @author: qiu.longjie
 * @create: 2025-05-29
 */
@WebFilter(urlPatterns = "/*")
@Order(100)
@Slf4j
@Component
public class EventTrackFilter implements Filter {
    @Autowired
    private TokenService tokenService;
    @Autowired
    private EventFilterConfigService eventFilterConfigService;
    @Autowired
    private EventHandleService eventHandleService;
    // 需要记录所有response的url
    private static final List<String> RECORD_ALL_RESPONSE_URL = Collections.singletonList("/dispatch/check.do");
    // 人脸识别校验接口 特殊处理
    private static final List<String> FACE_ID_CHECK_URL = Arrays.asList("/user/getTencentResult.do", "/user/getuqResult.do", "/user/getTencentResultLocal.do");

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        String uri = null;
        EventFilterConfigDO eventFilterConfig = null;
        try {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            uri = httpRequest.getRequestURI();

            // 如果当前URI不在需要埋点的列表中，直接放行，不进行任何请求/响应体的缓存和解析
            // 判断是否需要记录埋点
            eventFilterConfig = eventFilterConfigService.getByUri(uri);
            if (eventFilterConfig == null) {
                filterChain.doFilter(request, response);
                return; // 直接返回，跳过后续所有逻辑
            }
        } catch (Exception e) {
            // 稳准点还是调一下吧
            filterChain.doFilter(request, response);
            log.error("埋点过滤器异常", e);
            return;
        }

        CachedBodyHttpServletRequest wrappedRequest = new CachedBodyHttpServletRequest((HttpServletRequest) request);
        CachedBodyHttpServletResponse wrappedResponse = new CachedBodyHttpServletResponse((HttpServletResponse) response);
        try {
            //String requestBodyRaw = StreamUtils.copyToString(wrappedRequest.getInputStream(), StandardCharsets.UTF_8);
            // 放行
            filterChain.doFilter(wrappedRequest, wrappedResponse);
            // 拿到响应体
            wrappedResponse.getWriter().flush();
            // 写回客户端
            wrappedResponse.copyBodyToResponse();
            // 埋点逻辑放在单独的 try-catch 中
            //String uri = wrappedRequest.getRequestURI();
            try {
                // 判断是否需要记录埋点
                // 创建事件埋点参数
                EventPutDTO eventPutDTO = new EventPutDTO();
                eventPutDTO.setCommonHeader(getCommonHeader(wrappedRequest));
                eventPutDTO.setPutType("server_filter");
                eventPutDTO.setUri(uri);
                String token = wrappedRequest.getParameter("token");
                if (StrUtil.isEmpty(token)) {
                    token = wrappedRequest.getHeader("token");
                }
                if (StrUtil.isNotEmpty(token)) {
                    User user = tokenService.getUser(token);
                    if (user != null) {
                        eventPutDTO.setUserId(user.getUserId());
                        eventPutDTO.setUserPhone(user.getPhone());
                    }
                }
                setEventType(uri, wrappedRequest, eventPutDTO, eventFilterConfig);


                String responseBodyRaw = wrappedResponse.getContent();
                if (responseBodyRaw != null) {
                    // 特殊处理
                    Object jsonObject = JSON.parse(responseBodyRaw);
                    if (RECORD_ALL_RESPONSE_URL.contains(uri)) {
                        eventPutDTO.setResponseBody(JSON.toJSONString(jsonObject));
                    } else if (FACE_ID_CHECK_URL.contains(uri)){
                        // user/getTencentResult.do
                        // user/getuqResult.do
                        // user/getTencentResultLocal.do
                        // 人脸识别接口特殊处理。人脸识别结果写到detail字段里， 判断逻辑根据前端的逻辑相同res.ret && res.data
                        try {
                            if (jsonObject instanceof JSONObject) {
                                int ret = ((JSONObject) jsonObject).getIntValue("ret");
                                if (ret == 1){
                                    eventPutDTO.setDetail(((JSONObject) jsonObject).getString("data"));
                                }else {
                                    eventPutDTO.setDetail("false");
                                    eventPutDTO.setResponseBody(JSON.toJSONString(jsonObject));
                                }
                            }
                        } catch (Exception e) {
                            eventPutDTO.setDetail("false");
                            eventPutDTO.setResponseBody(JSON.toJSONString(jsonObject));
                        }
                    } else {
                        // 判断返回结果是否为成功响应，ret=1则为成功
                        if (jsonObject instanceof JSONObject && ((JSONObject) jsonObject).getIntValue("ret") != 1) {
                            eventPutDTO.setResponseBody(JSON.toJSONString(jsonObject));
                        }
                    }
                }
                // 压缩请求体JSON，去除换行符和多余空格
                //String requestBody = compactJsonString(requestBodyRaw);
                //eventPutDTO.setRequestBody(requestBody);
                // 设置完整的请求参数
                // 获取所有请求参数（包括URL参数和表单参数）
                //Map<String, Object> allRequestParams = getAllRequestParameters(wrappedRequest);
                //String requestParamsJson = JSON.toJSONString(allRequestParams);
                //eventPutDTO.setRequestParams(requestParamsJson);

                eventPutDTO.setEventTime(DateUtil.toLocalDateTime(new Date()));

                // 处理事件上报
                eventHandleService.handle(eventPutDTO);
            } catch (Exception e) {
                log.error("埋点处理异常，不影响业务,uri:{}", uri, e);
            }

        } catch (Exception e) {
            log.error("EventTrackFilter error.", e);
            // 如果前面没有成功写回，尝试写回
            try {
                if (!response.isCommitted()) {
                    wrappedResponse.copyBodyToResponse();
                }
            } catch (Exception responseException) {
                log.error("应急写回响应失败", responseException);
            }
        }
    }

    private static void setEventType(String uri, HttpServletRequest request, EventPutDTO eventPutDTO, EventFilterConfigDO eventFilterConfig) {
        eventPutDTO.setEventType(eventFilterConfig.getEventType());
        eventPutDTO.setEventDesc(eventFilterConfig.getEventDesc());
        // 特殊处理
        if ("/machine/finishOrder.do".equals(uri)) {
            String type = request.getParameter("type");
            /**type 为2则是人工结束订单，3是超时结束订单*/
            if ("2".equals(type)) {
                eventPutDTO.setEventType("manFinishOrder");
                eventPutDTO.setEventDesc("人工结束订单");
                eventPutDTO.setTraceId("");// 去掉系统自动生成的调用链traceId
            } else {
                eventPutDTO.setEventType("timeoutFinishOrder");
                eventPutDTO.setEventDesc("超时结束订单");
            }
            try {
                String userId = request.getParameter("userId");
                if (StrUtil.isNotEmpty(userId)){
                    eventPutDTO.setUserId(Integer.valueOf(userId));
                }
            } catch (Exception e) {
                log.error("/machine/finishOrder 埋点拦截 userId 设置异常", e);
            }
        }
    }

    /**
     * 获取所有请求参数（包括URL参数、表单参数、请求头）
     *
     * @param request HTTP请求
     * @return 包含所有参数的Map
     */
    private Map<String, Object> getAllRequestParameters(HttpServletRequest request) {
        Map<String, Object> allParams = new HashMap<>();

        // 1. 获取URL参数（Query Parameters）
        String queryString = request.getQueryString();
        if (StrUtil.isNotEmpty(queryString)) {
            allParams.put("queryString", queryString);
        }

        // 2. 获取所有请求参数（包括URL参数和表单参数）
        Map<String, String[]> parameterMap = request.getParameterMap();
        Map<String, Object> parameters = new HashMap<>();
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String key = entry.getKey();
            String[] values = entry.getValue();
            if (values.length == 1) {
                parameters.put(key, values[0]);
            } else {
                parameters.put(key, values);
            }
        }
        if (!parameters.isEmpty()) {
            allParams.put("parameters", parameters);
        }

        // 4. 获取基础请求信息
        Map<String, String> requestInfo = new HashMap<>();
        requestInfo.put("method", request.getMethod());
        requestInfo.put("requestURI", request.getRequestURI());
        requestInfo.put("remoteAddr", request.getRemoteAddr());
        requestInfo.put("contentType", request.getContentType());
        allParams.put("requestInfo", requestInfo);

        return allParams;
    }

    private CommonHeaderDTO getCommonHeader(CachedBodyHttpServletRequest request) {
        CommonHeaderDTO headerDTO = new CommonHeaderDTO();
        headerDTO.setAppId(request.getHeader("appId"));
        headerDTO.setSessionId(request.getHeader("sessionId"));
        headerDTO.setTraceId(request.getHeader("traceId"));
        if (StrUtil.isNotEmpty(request.getHeader("brandId"))) {
            headerDTO.setBrandId(Integer.parseInt(request.getHeader("brandId")));
        }
        if (StrUtil.isNotEmpty(request.getHeader("accountId"))) {
            headerDTO.setAccountId(Integer.parseInt(request.getHeader("accountId")));
        }
        return headerDTO;
    }

    /**
     * 压缩JSON字符串，去除换行符和多余空格
     *
     * @param jsonString 原始JSON字符串
     * @return 压缩后的JSON字符串
     */
    private String compactJsonString(String jsonString) {
        if (StrUtil.isEmpty(jsonString)) {
            return jsonString;
        }
        try {
            // 方案一：使用 fastjson 重新解析和序列化（推荐）
            Object jsonObject = JSON.parse(jsonString);
            return JSON.toJSONString(jsonObject);
        } catch (Exception e) {
            // 如果不是有效的JSON，则使用字符串处理方式去除换行符和多余空格
            return jsonString.replaceAll("\\s+", " ").trim();
        }
    }
}
